package org.lee.cr.future;

import lombok.extern.slf4j.Slf4j;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

/**
 * ProductRemoteService
 *
 * @author dralee
 * @date 2022-01-25 14:57:48
 **/
@Slf4j
public class ProductRemoteService {
    private Map<Integer, Product> cache = new HashMap<>();

    public ProductRemoteService() {
        cache.put(1, new Product(1, "apple"));
        cache.put(2, new Product(2, "orange"));
        cache.put(3, new Product(3, "computer"));
        cache.put(4, new Product(4, "mobile"));
        cache.put(5, new Product(5, "cat"));
    }

    private Product getLocal(int id) {
        return cache.get(id);
    }

    private Product getRemote(int id) {
        try {
            TimeUnit.MILLISECONDS.sleep(100);
            if (id == 666) {
                throw new RuntimeException("Evil request");
            }
        } catch (InterruptedException e) {
            log.error("remote call error:", e);
            e.printStackTrace();
        }
        return new Product(id, "name");
    }

    public CompletableFuture<Product> getProduct(int id) {
        try {
            Product product = getLocal(id);
            if (product == null) {
                CompletableFuture<Product> future = new CompletableFuture<>();
                Product p = getRemote(id);
                cache.put(id, p);
                future.complete(p);
                return future;
            }
            return CompletableFuture.completedFuture(product);
        } catch (Exception e) {
            log.error("remote call error:", e);
            CompletableFuture<Product> future = new CompletableFuture<>();
            future.completeExceptionally(e);
            return future;
        }
    }

    public CompletableFuture<Product> getProductAsync(int id) {
        try {
            Product product = getLocal(id);
            if (product == null) {
                return CompletableFuture.supplyAsync(() -> {
                    Product p = getRemote(id);
                    cache.put(id, p);
                    return p;
                });
            }
            return CompletableFuture.completedFuture(product);
        } catch (Exception e) {
            log.error("remote async call error:", e);
            CompletableFuture<Product> future = new CompletableFuture<>();
            future.completeExceptionally(e);
            return future;
        }
    }
}
